package models.ru.paralainer.chat.server.dao.impl;

import java.lang.reflect.ParameterizedType;

import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
import javax.persistence.NoResultException;
import javax.persistence.Query;

import models.ru.paralainer.chat.server.dao.GenericDAO;
import play.db.jpa.JPA;


/**
 * @param <T> entity type
 */
public abstract class GenericDAOImpl<T> implements GenericDAO<T> {

	private Class<T> persistentClass;


    @SuppressWarnings({"unchecked"})
    public GenericDAOImpl() {
        try {
            persistentClass = (Class<T>)
                    ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        } catch (ClassCastException e) {
            //can be raised when DAO is inherited twice
            persistentClass = (Class<T>)
                    ((ParameterizedType) getClass().getSuperclass().getGenericSuperclass()).getActualTypeArguments()[0];
        }
    }

	@SuppressWarnings("unchecked")
	public T findById(Long id, boolean lock) {
		T entity;
        if (lock) {
            entity = JPA.em().find(persistentClass, id, LockModeType.PESSIMISTIC_WRITE);
        } else {
            entity = JPA.em().find(persistentClass, id);
        }

		return entity;
	}

    public T findById(Long id) {
	     return findById(id, false);
	}
    
    

	@SuppressWarnings("unchecked")
	public T save(T entity) {
		JPA.em().persist(entity);
		return entity;
	}

	public void delete(T entity) {
        JPA.em().remove(entity);
	}
    
    @SuppressWarnings("unchecked")
    protected T singleResult(Query query){
        try {
            return (T) query.getSingleResult();
        }
        catch (NoResultException e) {
            return null;
        }
    }

}